require 'proxy_pump/helpers'
require 'proxy_pump/const'
module ProxyPump
  class Proxy

    class << self

      def create_table
        database.execute_batch Const::CREATE_PROXIES_TABLE_SQL
      end

      def drop_table
        database.execute Const::DROP_PROXIES_TABLE_SQL
      end

      def find(host, port)
        row = database.execute(Const::FIND_PROXY_SQL, host, port).first
        if row && !row.empty?
          row_to_proxy row
        end
      end

      def exists?(proxy)
        proxy = proxy.to_h
        result = database.execute(Const::EXISTS_PROXY_SQL, proxy[:host], proxy[:port]).first[0]
        result && result.to_i > 0
      end

      def empty
        database.execute Const::EMPTY_PROXIES_SQL
      end
      alias_method :delete_all, :empty

      def to_cache(interval)
        datetime = ProxyPump::Helpers.sqlite_ftime(Time.now.utc - interval.to_i)
        database.execute(Const::CACHE_PROXIES_SQL, datetime) { |row| yield row_to_proxy(row) }
      end

      def to_verify(interval, &block)
        datetime = ProxyPump::Helpers.sqlite_ftime(Time.now.utc - interval.to_i)
        database.execute(Const::VERIFY_PROXIES_SQL, datetime) { |row| yield row_to_proxy(row) }
      end

      def database
        ProxyPump.database
      end

      private

        def row_to_proxy(row)
          attrs = Const::PROXIES_TABLE_COLUMNS.zip(row).to_h
          new attrs
        end

    end

    attr_accessor :host, :port
    attr_accessor :anon, :protocal
    attr_accessor :country, :province, :city, :area, :isp
    attr_accessor :elapsed, :score
    attr_accessor :created_at, :updated_at, :last_verified_at
    attr_accessor :source_name, :source_url

    def initialize(options = {})
      assign_attrs options
    end

    def valid?
      valid_ip? && valid_port?
    end

    def valid_ip?
      ProxyPump::Helpers.valid_ip?(host)
    end

    def valid_port?
      ProxyPump::Helpers.valid_port?(port)
    end

    def anonymous?
      !!anon
    end

    def ping?
      !elapsed.nil?
    end
    alias_method :useful?, :ping?

    def trashy?
      verified? && !ping?
    end

    def verified?
      !!last_verified_at
    end

    def fast?
      elapsed && elapsed <= 1000
    end

    def middle?
      elapsed && elapsed > 1000 && elapsed <= 1500
    end

    def slow?
      elapsed && elapsed > 1500
    end

    def ipinfo=(ipinfo)
      if ipinfo
        @host     = ipinfo[:ip]
        @country  = ipinfo[:country]
        @province = ipinfo[:province]
        @city     = ipinfo[:city]
        @area     = ipinfo[:area]
        @isp      = ipinfo[:isp]
      end
    end

    def faster_than?(other)
      other.is_a?(self.class) &&
      other.elapsed &&
      self.elapsed &&
      self.elapsed < other.elapsed
    end

    def full_address
      "#{host}:#{port}"
    end

    def to_s
      full_address
    end

    def to_h
      {
        host: host,
        port: port,
        anon: anon,
        protocal: protocal,
        country: country,
        province: province,
        city: city,
        area: area,
        isp: isp,
        elapsed: elapsed,
        last_verified_at: last_verified_at,
        created_at: created_at,
        updated_at: updated_at,
        source_name: source_name,
        source_url: source_url
      }
    end

    def inspect
      to_h
    end

    def delete(&callback)
      self.class.database.execute Const::DELETE_PROXY_SQL, host, port
      if block_given?
        yield
      end
    end

    def update(&callback)
      self.class.database.execute(Const::UPDATE_PROXY_SQL, country, province, city, area, isp, last_verified_at, elapsed, score, updated_at, host, port)
      if block_given?
        yield
      end
    end

    def save(&block)
      self.class.database.execute(Const::INSERT_PROXY_SQL, host, port, anon, protocal, country, province, city, area, isp, last_verified_at, elapsed, score, source_name, source_url, created_at, updated_at)
      if block_given?
        yield
      end
    end

    private

      def assign_attrs(hash)
        Const::PROXIES_TABLE_COLUMNS.each do |column|
          self.public_send :"#{column}=", hash[:"#{column}"]
        end
      end

  end # Proxy
end # ProxyPump
